﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Xml;

namespace svg2wkt
{
    class Converter
    {
        private string _fileName;
        public string FileName
        {
            get { return _fileName; }
            set
            {
                _fileName = value;
            }
        }
        private string _errorMessage;
        public string ErrorMessage
        {
            get { return _errorMessage; }
            set
            {
                _errorMessage = value;
            }
        }


        private string sqlQuery = "";
        struct BordersInt
        {
            public int top, bottom, left, right;
        }
        struct BordersFloat
        {
            public float top, bottom, left, right;
        }
        struct textNode
        {
            public float value;
            public int x, y;
        }
        struct point
        {
            public float x, y;
        }
        public Converter(string fileName)
        {
            _fileName = fileName;
            System.Globalization.CultureInfo customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberDecimalSeparator = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

        }
        public int Process()
        {
            XmlDocument svgDocument = new XmlDocument();
            try
            {
                svgDocument.Load(_fileName);
            }
            catch(Exception ex)
            {
                _errorMessage = ex.ToString();
                return -1;
            }
            List<XmlNode> polylines = new List<XmlNode>();
            List<XmlNode> textNodes = new List<XmlNode>();
            List<textNode> textNodesProcessed = new List<textNode>();
            List<point> multiline = new List<point>();
            foreach (XmlNode node in svgDocument.DocumentElement.ChildNodes)
                findSpecificNode(node, "polyline", ref polylines);
            foreach (XmlNode node in svgDocument.DocumentElement.ChildNodes)
                findSpecificNode(node, "text", ref textNodes);
            if (polylines.Count >= 3)
            {
                BordersInt actualBorders = new BordersInt();
                string coordinates = polylines[1].Attributes["points"].Value.Trim().Replace(",", " ");
                string[] coordinatesArray = coordinates.Split(' ');
                actualBorders.left = Convert.ToInt32(coordinatesArray[0]);
                actualBorders.top = Convert.ToInt32(coordinatesArray[1]);
                actualBorders.right = Convert.ToInt32(coordinatesArray[2]);
                coordinates = polylines[2].Attributes["points"].Value.Trim().Replace(",", " ");
                coordinatesArray = coordinates.Split(' ');
                actualBorders.bottom = Convert.ToInt32(coordinatesArray[1]);
                //Borders declaredBorders = new Borders();
                foreach (XmlNode node in textNodes)
                {
                    textNode tn = new textNode();
                    //tn.text = node.Value;
                    XmlNode parentNode = node.ParentNode;
                    coordinates = parentNode.Attributes["transform"].Value.Replace("matrix(", "").Replace(")", "");
                    coordinatesArray = coordinates.Split(',');
                    tn.x = Convert.ToInt32(coordinatesArray[4]);
                    tn.y = Convert.ToInt32(coordinatesArray[5]);
                    try
                    {
                        float number = Single.Parse(node.InnerText);
                        tn.value = number;
                        textNodesProcessed.Add(tn);
                    }
                    catch { }
                }
                BordersFloat declaredBorders = new BordersFloat();
                declaredBorders.left = textNodesProcessed[0].value;
                declaredBorders.right = textNodesProcessed[0].value;
                declaredBorders.top = textNodesProcessed[textNodesProcessed.Count - 1].value;
                declaredBorders.bottom = textNodesProcessed[textNodesProcessed.Count - 1].value;
                int commonY = textNodesProcessed[0].y;
                foreach (textNode tn in textNodesProcessed)
                    if (tn.y == commonY)
                    {
                        if (tn.value < declaredBorders.left)
                            declaredBorders.left = tn.value;
                        if (tn.value > declaredBorders.right)
                            declaredBorders.right = tn.value;
                    }
                    else
                    {
                        if (tn.value < declaredBorders.bottom)
                            declaredBorders.bottom = tn.value;
                        if (tn.value > declaredBorders.top)
                            declaredBorders.top = tn.value;
                    }
                /*textBox2.Text = actualBorders.left.ToString() + " " + actualBorders.right.ToString() + " " + actualBorders.bottom.ToString() + " " + actualBorders.top.ToString() + " ";
                textBox2.Text += declaredBorders.left.ToString() + " " + declaredBorders.right.ToString() + " " + declaredBorders.bottom.ToString() + " " + declaredBorders.top.ToString();*/

                coordinates = polylines[0].Attributes["points"].Value.Replace(",", " ").Trim();
                coordinatesArray = coordinates.Split(' ');
                for (int i = 0; i < coordinatesArray.Length / 2; i++)
                {
                    try
                    {
                        point p = new point();
                        p.x = Single.Parse(coordinatesArray[i * 2]);
                        p.y = Single.Parse(coordinatesArray[i * 2 + 1]);
                        multiline.Add(p);
                    }
                    catch (Exception ex)
                    {
                        _errorMessage = ex.ToString();
                        return -1;
                    }
                }
                float xMultiplier = (declaredBorders.right - declaredBorders.left) / (actualBorders.right - actualBorders.left);
                float yMultiplier = -1 * (declaredBorders.top - declaredBorders.bottom) / (actualBorders.top - actualBorders.bottom);
                for (int i = 0; i < multiline.Count; i++)
                {
                    point p = new point();
                    p.x = (multiline[i].x - actualBorders.left) * xMultiplier + declaredBorders.left;
                    p.y = (multiline[i].y - actualBorders.bottom) * yMultiplier + declaredBorders.top;
                    multiline[i] = p;
                }
                string result = "DECLARE @g geometry; \nDECLARE @h geometry;\n SET @g = geometry::STGeomFromText('MULTILINESTRING((";
                foreach (point p in multiline)
                    result += p.x.ToString() + " " + p.y.ToString() + ", ";
                result = result.Remove(result.Length - 2) + "))', 0).MakeValid() \n";
                result += "SET @h = geometry::STGeomFromText('POLYGON ((" + declaredBorders.left.ToString() + " " + declaredBorders.top.ToString() + ",";
                result += declaredBorders.right.ToString() + " " + declaredBorders.top.ToString() + ",";
                result += declaredBorders.right.ToString() + " " + declaredBorders.bottom.ToString() + ",";
                result += declaredBorders.left.ToString() + " " + declaredBorders.bottom.ToString() + ",";
                result += declaredBorders.left.ToString() + " " + declaredBorders.top.ToString() + "))', 0).MakeValid()";
                result += "\n Insert into Graphs(Graph, FileName) values((SELECT @g.STIntersection(@h)), '" + _fileName + "')" ;
                sqlQuery = result;
                return 0;
            }
            return -1;
        }

        private void findSpecificNode(XmlNode node, string specificNodeName, ref List<XmlNode> targetList)
        {
            if (node.Name == specificNodeName)
                targetList.Add(node);
            foreach (XmlNode childNode in node.ChildNodes)
                findSpecificNode(childNode, specificNodeName, ref targetList);
        }


        public int SaveToDatabase(string connectionString)
        {
            try
            {
                using (SqlConnection sqlConnection = new SqlConnection(connectionString))
                {
                    SqlCommand command = new SqlCommand(sqlQuery, sqlConnection);
                    sqlConnection.Open();
                    int rowsQty = command.ExecuteNonQuery();
                    sqlConnection.Close();
                    if (rowsQty == 1)
                        return 0;
                }
            }
            catch (Exception ex)
            {
                _errorMessage = ex.ToString();
                return -1;
            }
            return -1;
        }
    }
}
